#include "Drv_AD9854.h"


/* IO set */
// 接线备注
// {RT, SP, A2, A0, UD, WR, RD}
// [板上标注] (芯片引脚) 功能
// [RT] (MASTER RESET) master reset

// [SP] (S/P SELECT) serial/parallel

// [A2] (A2/IO RESET) resetting the serial bus 

// [A0] (A1/SDO)
// spi_mosi, SDIO is used in 2-wire serial communication mode.

// [UD] (I/O UD CLK)
// a rising edge transfers the contents of the I/O port buffers to the programming registers

// [WR] (WR/SCLK) spi_scl 

// [RD] (RD/CS) chip select 

#define USE_BITBAND (0)
#if USE_BITBAND
    #define reset(x)
    #define cs(x)
    #define sp(x)
    #define io_reset(x)
    #define updateClk(x)
    #define spi_scl(x)
    #define spi_mosi(x)
#else
    #define reset(x)        HAL_GPIO_WritePin(AD9854_RT_GPIO_Port, AD9854_RT_Pin, (x) ?GPIO_PIN_SET :GPIO_PIN_RESET)
    #define cs(x)           HAL_GPIO_WritePin(AD9854_RD_GPIO_Port, AD9854_RD_Pin, (x) ?GPIO_PIN_SET :GPIO_PIN_RESET)
    #define sp(x)           HAL_GPIO_WritePin(AD9854_SP_GPIO_Port, AD9854_SP_Pin, (x) ?GPIO_PIN_SET :GPIO_PIN_RESET)
    #define io_reset(x)     HAL_GPIO_WritePin(AD9854_A2_GPIO_Port, AD9854_A2_Pin, (x) ?GPIO_PIN_SET :GPIO_PIN_RESET)
    #define updateClk(x)    HAL_GPIO_WritePin(AD9854_UD_GPIO_Port, AD9854_UD_Pin, (x) ?GPIO_PIN_SET :GPIO_PIN_RESET)
    #define spi_scl(x)      HAL_GPIO_WritePin(AD9854_WR_GPIO_Port, AD9854_WR_Pin, (x) ?GPIO_PIN_SET :GPIO_PIN_RESET)
    #define spi_mosi(x)     HAL_GPIO_WritePin(AD9854_A0_GPIO_Port, AD9854_A0_Pin, (x) ?GPIO_PIN_SET :GPIO_PIN_RESET)
#endif


/* reg set */
// Phase Adjust
#define PA1     (0x00)
#define PA2     (0x01)
// Frequency Turning Word
#define FTW1    (0x02)
#define FTW2    (0x03)
// Dleta Frequency Word
#define DFW     (0x04)
// Update Clock
#define UClk    (0x05)
// Ramp Rate Clock
#define RRClk   (0x06)
// Control
#define CTRL    (0x07)
// Output Shaped Keying I/Q Multiplier
#define OSKIM   (0x08)
#define OSKQM   (0x09)
// Output Shaped Keying Ramp Rate
#define OSKRR   (0x0A)
// QDAC
#define QDAC    (0x0B)


void sendByte(uint8_t byte)
{
    uint32_t i;

    for(i = 0; i < 8; ++i)
    {
        spi_mosi( (byte & 0x80) );
        byte <<= 1;
        spi_scl(0);
        spi_scl(1);
    }
}

void writeReg(uint8_t addr, uint8_t* pData, uint8_t numOfByte)
{
    uint32_t i;

    io_reset(1);
    HAL_Delay(1);
    io_reset(0);
    sendByte(addr);
    for(i = 0; i < numOfByte; ++i)
    {
        sendByte(pData[i]);
    }
}

/*
 * FTW = (Desired Output Frequency × 2**N)/SYSCLK
 * N = 48, SYSCLK = 30M * 10
 * 2**48 / 300M =  938250
 */
void getFTW(double fre, uint8_t* pData)
{
    double tmp;
    uint16_t H16;
    uint32_t L32;

    tmp = fre * 938249.922369;
    H16 = tmp / 4294967296;
    L32 = tmp - (H16 * 4294967296);
    pData[0] = (uint8_t)(H16 >> 8);
    pData[1] = (uint8_t)(H16);
    pData[2] = (uint8_t)(L32 >> 24);
    pData[3] = (uint8_t)(L32 >> 16);
    pData[4] = (uint8_t)(L32 >> 8);
    pData[5] = (uint8_t)(L32);
}

void AD9854_Init()
{
    uint8_t data4CTRL[4] = {0x00, 0x0A, 0x00, 0x60};
    uint8_t dataAmp[2]   = {0x0F, 0xFF};
    uint8_t dataFre[6]   = {0};

    HAL_Delay(5);

    sp(0);
    spi_scl(0);
    updateClk(0);

    reset(1);
    HAL_Delay(10);
    reset(0);

    cs(0);
    io_reset(0);
    
    writeReg(CTRL, data4CTRL, 4);
    updateClk(1);
    updateClk(0);

    // default output 1M sin full amp
    writeReg(OSKIM, dataAmp, 2);
    writeReg(OSKQM, dataAmp, 2);

    getFTW(1000000, dataFre);
    writeReg(FTW1,  dataFre, 6);
    updateClk(1);
    updateClk(0);
}

void AD9854_setAmp(uint32_t Amp)
{
    uint8_t dataAmp[2] = {0};

    dataAmp[0] = (uint8_t)(Amp >> 8);
    dataAmp[1] = (uint8_t)(Amp);
    writeReg(OSKIM, dataAmp, 2);
    writeReg(OSKQM, dataAmp, 2);
    updateClk(1);
    updateClk(0);
}

void AD9854_setFre(uint32_t Fre)
{
    uint8_t dataFre[6]   = {0};

    getFTW(Fre, dataFre);
    writeReg(FTW1,  dataFre, 6);
    updateClk(1);
    updateClk(0);
}
